#include "signin.srpc.h"
#include "workflow/WFFacilities.h"
#include "../../include/CryptoUtil.h"
#include "workflow/MySQLResult.h"
#include <iostream>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>

#include <wfrest/HttpServer.h>
#include <chrono>
#include "ppconsul/agent.h"

using ppconsul::Consul;
using namespace ppconsul::agent;
using namespace wfrest;

using namespace srpc;
using namespace protocol;
using std::string;
using std::vector;
using std::cout;
using std::endl;
using json = nlohmann::json;

static WFFacilities::WaitGroup wait_group(1);

void sig_handler(int signo)
{
	wait_group.done();
}

struct SigninMysqlCallbackNeed {
    SigninResponse * resp;
    string username;
    string password;
};

void mysql_callback(WFMySQLTask* task)
{
	// 使用查询得到的盐值，对用户上传的密码进行哈希
	// 比对生成的哈希和数据库中存入的哈希
	// 校验成功，生成 Token
	// 返回客户端Json字符串

	// 获取原函数的resp回复报文，可在下面直接设置回复报文内容
	SigninMysqlCallbackNeed *smcn = (SigninMysqlCallbackNeed *)task->user_data;

    // 1. 判断任务是否成功, 不成功回复 不成功 与 错误信息
    int state = task->get_state();
    if (state != WFT_STATE_SUCCESS) {
		string err_string = WFGlobal::get_error_string(state, task->get_error());
        cout << "[Error]: " <<  err_string << "\n\n";
        smcn->resp->set_success(false);
		smcn->resp->set_message("signin " + err_string);
		return ;
    }

	// 2. 处理结果集
    MySQLResponse* resp = task->get_resp();
    MySQLResultCursor cursor { resp };
    if (cursor.get_cursor_status() == MYSQL_STATUS_GET_RESULT) {
		vector<MySQLCell> record;
		string hash_password;
		string salt;
		if (cursor.fetch_row(record)) {
			hash_password = record[0].as_string();
			salt = record[1].as_string();

			cout << "fetch [hash_password]: " << hash_password << "   [salt]: " << salt << endl;
			
			// 对用户密码hash， 并对比
			if (hash_password == CryptoUtil::hash_password(smcn->password, salt)) {
				// 成功， 生成Token
				string token = CryptoUtil::generate_token(smcn->username);

				cout << "[token]: " << token << endl;

				// 返回JSON
				json j;
				j["data"]["Username"] = smcn->username;
				j["data"]["Token"] = token;
				j["data"]["Location"] = "/static/view/home.html";
				cout << "[json]:\n" << j.dump(2) << endl;

				smcn->resp->set_success(true);
				smcn->resp->set_message(j.dump());

				cout << "Signin OK.\n";
			}
			else {
				smcn->resp->set_success(false);
				smcn->resp->set_message("signin user password error");
				cout << "signin user password error\n\n";
				return;
			}

			cout << endl;
		}
    }
}


class SigninServiceImpl : public Signin::Service
{
public:

	void Signin(SigninRequest *request, SigninResponse *response, srpc::RPCContext *ctx) override
	{
		cout << "\nIn Signin:" << endl;

		// 解析客户端的请求参数
		string username = request->username();
		string password = request->password();

		cout << "[username]: " << username << "   [password]: " << password << endl;

		// 创建MYSQL任务
		// 使用查询得到的盐值，对用户上传的密码进行哈希
		// 比对生成的哈希和数据库中存入的哈希
		// 校验成功，生成 Token
		// 返回客户端Json字符串

		// 查询数据库
		//   1. 创建任务
		const string url = "mysql://root@localhost/cpp65";
		const int retry_max = 3;
		WFMySQLTask* task = WFTaskFactory::create_mysql_task(url, retry_max, mysql_callback);    
	
		//   2. 设置请求
		string sql = "SELECT password, salt FROM tbl_user WHERE tomb = 0 AND username = '" + username + "'";
		MySQLRequest* req = task->get_req();
		req->set_query(sql);
		cout << "[MYSQL] " << sql << endl;

		//   3. 设置 user_data 为 SigninResponse *response，传入回调函数
		task->user_data = new SigninMysqlCallbackNeed{response, username, password};

		//   4. 将WFMySQLTask放入SeriesWork中
        ctx->get_series()->push_back(task);

	}
};

void timer_callback(WFTimerTask* task)
{
    SeriesWork* series = series_of(task);
    Agent* agent = static_cast<Agent*>(series->get_context());

    // 发送心跳包
    agent->servicePass("signin");
    // 创建另一个定时任务
    WFTimerTask* nextTask = WFTaskFactory::create_timer_task(7, 0, timer_callback);
    series->push_back(nextTask);
}

int main()
{
	GOOGLE_PROTOBUF_VERIFY_VERSION;
	unsigned short port = 4818;
	SRPCServer server;

	SigninServiceImpl signin_impl;
	server.add_service(&signin_impl);
	server.start(port);

	HttpServer hserver {};
	hserver.start(port);

	// 指定注册中心 Consul 的ip地址，端口和数据中心
	Consul consul { "http://127.0.0.1:8500", ppconsul::kw::dc="dc1" };
	// 创建代理
	Agent agent { consul };
	// 注册服务 
	agent.registerService(
		kw::id = "signin",
		kw::name = "UserService",
		kw::address = "127.0.0.1",
		kw::port = 4818,
		kw::check = TtlCheck(std::chrono::seconds{ 10 })
	);

	// 定时发送心跳包
	WFTimerTask* timerTask = WFTaskFactory::create_timer_task(7, 0, timer_callback);

	SeriesWork* series = Workflow::create_series_work(timerTask, nullptr);
	series->set_context(&agent);    // 设置序列的上下文
	series->start();

	wait_group.wait();

	server.stop();
	hserver.stop();
	google::protobuf::ShutdownProtobufLibrary();
	return 0;
}
